<template>
  <div class="gis-layer-management">
    <div class="header">
      <div class="header-title">
        <span class="type-icon-name">
          <span class="header-name">标记</span>
        </span>
      </div>
    </div>
    <!-- 图层列表 -->
    <div class="layer-tag-content four-scroll-y">
      <a-divider>图层标记</a-divider>
      <div class="value-select">
        <a-select
          v-model="currentFeatureType"
          :style="{ width: `calc(100% - 30px)` }"
          size="small"
          @change="featureTypeHandleChange"
        >
          <a-select-option
            v-for="item in selectFeatureTypeOptions"
            :key="item.type"
            :value="item.type"
          >
            {{ item.name }}
          </a-select-option>
        </a-select>
        <!-- 全局配色 -->
        <div class="color-select">
          <a-popover
            trigger="click"
            placement="right"
            :overlay-class-name="'gis-popover-color-picker'"
            :visible="globalColorPopoverVisible"
            :arrow-point-at-center="true"
          >
            <span
              :style="{
                cursor: 'pointer',
                'background-color': globalColor,
                opacity: currentGlobalColorOpacity,
              }"
              class="select-color-popover"
              @click.stop="openGlobalColorPopover"
            ></span>
            <div slot="content" @click.stop>
              <!-- 颜色拾取 :disable-alpha="true" 可输入 disable-fields: 透明度 -->
              <sketch v-model="sketchColor" :disable-fields="true" />
              <div class="cancel-confirm">
                <a-button
                  key="back"
                  size="small"
                  class="cancel-button"
                  @click="globalColorPopoverVisible = false"
                >
                  取消
                </a-button>
                <a-button
                  key="submit"
                  type="primary"
                  size="small"
                  @click="globalColorHandleOk"
                >
                  确定
                </a-button>
              </div>
            </div>
          </a-popover>
        </div>
      </div>

      <div class="no-text-divider">
        <a-divider />
      </div>

      <!-- 属性配置 -->
      <div class="tag-list">
        <!-- 颜色 -->
        <div
          class="tag-item"
          :class="{ 'tag-item-active': discreteColorVisible }"
          @click="shortcutEditColor"
        >
          <span class="tag-item-icon">
            <a-icon-font :type="'iconyanse'" />
          </span>
          <span class="tag-item-text">颜色</span>
        </div>
        <!-- 大小 -->
        <a-popover
          trigger="click"
          placement="bottomLeft"
          :overlay-class-name="'gis-popover-size-slider'"
          :visible="tagSizeVisible"
        >
          <div
            class="tag-item"
            :class="{ 'tag-item-active': tagSizeVisible }"
            @click.stop="shortcutEditSize"
          >
            <span class="tag-item-icon">
              <a-icon-font :type="'icondaxiao'" />
            </span>
            <span class="tag-item-text">大小</span>
          </div>
          <a-slider
            slot="content"
            v-model="featureSize"
            range
            :max="50"
            :min="1"
            @change="changeFeatureSize"
          />
        </a-popover>
        <!-- 标签 -->
        <a-popover
          trigger="click"
          placement="bottomLeft"
          :overlay-class-name="'gis-popover-label'"
          :visible="tagLabelVisible"
        >
          <div
            class="tag-item"
            :class="{ 'tag-item-active': tagLabelVisible }"
            @click.stop="shortcutEditLabel"
          >
            <span class="tag-item-icon">
              <a-icon-font :type="'iconwenzi'" />
            </span>
            <span class="tag-item-text">标签</span>
          </div>
          <!-- 标签配置气泡框 -->
          <tag-label
            slot="content"
            :layout="labelLayoutConfig"
            @cancel="tagLabelVisible = false"
            @confirm="confirmEditLabelSetting"
          />
        </a-popover>
        <!-- 详情 -->
        <div class="tag-item" @click="editDetail">
          <span class="tag-item-icon">
            <a-icon-font :type="'iconxiangxixinxi'" />
          </span>
          <span class="tag-item-text">详情</span>
        </div>
      </div>
      <div class="tag-setting-list">
        <div
          v-for="(attributeTag, index) in attributesAdded"
          :key="index"
          class="setting-list-item"
        >
          <a-dropdown :trigger="['click']">
            <div class="ant-dropdown-icon">
              <a-icon-font :type="iconMap[attributeTag.tagType]" />
              <a-icon-font type="iconicon-beifen" />
            </div>
            <a-menu
              slot="overlay"
              size="small"
              :selected-keys="[attributeTag.type || 'null']"
              @click="($event) => tagTypeChange($event, attributeTag, index)"
            >
              <a-menu-item key="color">
                <a-icon-font type="iconyanse" />
                <span>颜色</span>
              </a-menu-item>
              <a-menu-item key="size">
                <a-icon-font type="icondaxiao" />
                <span>大小</span>
              </a-menu-item>
              <a-menu-item key="label">
                <a-icon-font type="iconwenzi" />
                <span>标签</span>
              </a-menu-item>
              <a-menu-item key="detail">
                <a-icon-font type="iconxiangxixinxi" />
                <span>详情</span>
              </a-menu-item>
            </a-menu>
          </a-dropdown>
          <div class="attribute-tag-item">
            <span class="item-name text-overflow-ellipsis">
              {{ attributeTag.name }}
            </span>
            <a-tooltip placement="top" :mouse-enter-delay="1">
              <template slot="title">
                <span>删除属性标记</span>
              </template>
              <span
                class="delete-attribute-tag"
                @click="deleteAttributeTag(attributeTag.tagType, index)"
              >
                <a-icon-font type="icontianjiachengyuan" />
              </span>
            </a-tooltip>

            <a-dropdown :trigger="['click']">
              <div class="ant-dropdown-icon">
                <a-icon-font type="iconicon-beifen" />
              </div>
              <a-menu
                slot="overlay"
                size="small"
                @click="($event) => menuAction($event, attributeTag, index)"
              >
                <a-menu-item
                  v-show="attributeTag.tagType !== 'detail'"
                  key="edit"
                  >编辑</a-menu-item
                >
                <a-menu-item key="delete">删除</a-menu-item>
                <a-menu-item key="view-source-data">查看源数据</a-menu-item>
              </a-menu>
            </a-dropdown>
          </div>
        </div>
      </div>
    </div>
    <!-- 离散配色板 -->
    <discrete-color-setting-popup
      :visible="discreteColorVisible"
      :discrete-values="discreteValues"
      :layer-type="layerType ? layerType : ''"
      :theme="colorThemeSettingConfig"
      @cancel="discreteColorVisible = false"
      @confirm="discreteColorConfirm"
    />
    <!-- 连续配色板 -->
    <successive-color-setting-popup
      :visible="successiveColorVisible"
      :successive-values="successiveValues"
      :layer-type="layerType ? layerType : ''"
      :theme="colorThemeSettingConfig"
      @cancel="successiveColorVisible = false"
      @confirm="successiveColorConfirm"
    />
  </div>
</template>

<script lang="ts">
/**
 * gis 标记
 */
import { Vue, Component, Prop, Watch } from 'vue-property-decorator'
import { Sketch } from 'vue-color'
import TagLabel from '@/components/gis/layer-tags/TagLabel.vue'
import DiscreteColorSettingPopup from '@/components/gis/layer-tags/DiscreteColorSettingPopup.vue'
import SuccessiveColorSettingPopup from '@/components/gis/layer-tags/SuccessiveColorSettingPopup.vue'
import GisStore from '@/store/modules/gis'
import mapUtils from '@/components/gis/map-package/map-utils'
import { debounce } from 'lodash'
import {
  tabTypeIconMap,
  paintPropertyNameMap,
  paintPropertyOpacityNameMap,
  defaultLabelTagLayerStyle,
} from '@/components/gis/layer-tags/attribute-tag/tags'
import { Modal } from 'ant-design-vue'

import generateSizeGradient from '@/components/gis/layer-tags/attribute-tag/tag-size-utils'

@Component({
  components: {
    Sketch,
    TagLabel,
    DiscreteColorSettingPopup,
    SuccessiveColorSettingPopup,
  },
})
export default class LayerTags extends Vue {
  @Prop({ type: Number, default: 0 }) projectId!: number // 项目id
  private iconMap: any = tabTypeIconMap // 标记类型 icon

  // 全局要素形状配置
  public currentFeatureType: any = 'circle' // 当前选择的亚搜类型
  public tagTypeOptions: any = {
    circle: [
      { name: '圆', type: 'circle' },
      // { name: '三角形', type: 'triangle' },
      // { name: '正方形', type: 'square' },
    ],
    line: [
      { name: '实线', type: 'solid-line' },
      { name: '虚线', type: 'dotted-line' },
    ],
    fill: [{ name: '纯色面', type: 'pure-color-polygon' }],
  }

  // 全局要素颜色配置
  public globalColor: any = '#7A88F2' // 全局颜色配置
  public currentGlobalColorOpacity = 1 // 全局颜色透明度
  public sketchColor: any = '#7A88F2' // 全局颜色配置
  public globalColorPopoverVisible: boolean = false // 全局颜色设定气泡框

  // 属性标记-颜色配置
  public discreteColorVisible: boolean = false // 离散颜色配置 modal
  public successiveColorVisible: boolean = false // 连续颜色配置 modal

  //  属性标记-尺寸配置
  public featureSize: number[] = [5, 10] // 点的大小, 线宽
  public tagSizeVisible: boolean = false // 点的大小, 线宽编辑框

  //  属性标记-标签配置
  public tagLabelVisible: boolean = false // 标签的修改 popover
  public tabLabelFontFamily: string = '' // 字体
  public tabLabelFontSize: number = 12 // 字体大小
  public labelLayoutConfig: any = {} // 用户标签配置，用于回显

  // 属性列表展示图层选中的数据源中的字段，默认展示第一图层的数据字段
  public get currentLayer() {
    return GisStore.selectLayer || GisStore.firstLayerOfList
  }
  // 图层类型
  public get layerType() {
    return this.currentLayer ? this.currentLayer.type : null
  }
  // 要素形状标记选择项
  public get selectFeatureTypeOptions() {
    return this.currentLayer ? this.tagTypeOptions[this.currentLayer.type] : []
  }
  // 属性标记列表
  public get attributesAdded() {
    return GisStore.attributeTag
  }

  public mounted() {
    document.addEventListener('click', this.onDocumentClick)
    this.$once('hook:beforeDestroy', () => {
      document.removeEventListener('click', this.onDocumentClick)
    })
  }

  /**
   * 点击关闭气泡框
   */
  public onDocumentClick() {
    this.globalColorPopoverVisible = false
    this.tagLabelVisible = false
    this.tagSizeVisible = false
  }

  /**
   * 选择的当前图层变化
   * @param id
   */
  @Watch('currentLayer.id')
  public onCurrentLayer(id: any) {
    GisStore.clearLayerAttributeFieldStatistic()
    if (!id) {
      GisStore.setCurrentLayerTagInfo({})
      return
    }
    const { tagInfo } = this.currentLayer.data
    this.currentFeatureType = tagInfo.globalInfo.featureType // 全局要素标记
    this.globalColor = tagInfo.globalInfo.globalColor
    this.currentGlobalColorOpacity = tagInfo.globalInfo.globalOpacity
    // 需结合透明度转成16进制
    const opacityHex = Math.round(
      255 * this.currentGlobalColorOpacity
    ).toString(16)
    this.sketchColor = tagInfo.globalInfo.globalColor + opacityHex
    GisStore.setCurrentLayerTagInfo(tagInfo)
    this.initSizeTagTypeConfig()
  }

  /**
   * 解析用户的大小配置进行回显
   */
  private initSizeTagTypeConfig() {
    const sizeTag = this.attributesAdded.find(
      (tagInfo: any) => tagInfo.tagType === 'size'
    )
    if (sizeTag && Array.isArray(sizeTag.config.size)) {
      this.featureSize = sizeTag.config.size
    }
  }

  /**
   * 解析用户的标签配置进行回显
   */
  private initlabelTagTypeConfig() {
    const labelTag = this.attributesAdded.find(
      (tagInfo: any) => tagInfo.tagType === 'label'
    )
    if (labelTag && labelTag.config.layout) {
      this.labelLayoutConfig = {
        ...labelTag.config.layout,
        'text-color': labelTag.config.paint['text-color'],
        'text-opacity': labelTag.config.paint['text-opacity'],
      }
    }
  }

  /**
   * 修改标记类型
   */
  public async featureTypeHandleChange(value: any) {
    if (this.currentLayer.type === 'line') {
      const dasharray: number[] = value === 'dotted-line' ? [2, 2] : [1]
      GisStore.mapboxInstance.setPaintProperty(
        String(this.currentLayer.id),
        'line-dasharray',
        dasharray
      )
      GisStore.editTagInfoGlobalInfo({
        paint: {
          'line-dasharray': dasharray,
        },
      })
      await GisStore.gisSaveTabInfoWithLayer()
    }
  }

  /**
   * 打开全局颜色设定
   */
  public openGlobalColorPopover() {
    this.tagLabelVisible = false
    if (!this.globalColorPopoverVisible) {
      this.sketchColor = {
        hex: this.globalColor,
        a: this.currentGlobalColorOpacity,
      }
    }
    this.globalColorPopoverVisible = !this.globalColorPopoverVisible
  }

  /**
   * 全局颜色设定 确定
   * 当下方有属性设定为颜色时，将其设置为详情
   */
  public async globalColorHandleOk() {
    const attributeTag: any = this.attributesAdded.find(
      (attribute: any) => attribute.tagType === 'color'
    )
    this.globalColorPopoverVisible = false
    if (attributeTag) {
      Modal.confirm({
        title: '已存在颜色标记属性！',
        content: '标记属性中已存在颜色标记属性，是否覆盖？',
        centered: true,
        okText: '确定',
        cancelText: '取消',
        onOk: this.globalColorHandleOkPass,
      })
    } else {
      await this.globalColorHandleOkPass(false)
    }
  }

  /**
   * 全局颜色设定 确定
   * 当下方有属性设定为颜色时，将其设置为详情
   */
  public async globalColorHandleOkPass(cover: boolean = true) {
    // 覆盖原有的颜色属性标记
    if (cover) {
      const checkAttributeTag: any = this.attributesAdded.find(
        (attributeTag: any) => attributeTag.tagType === 'color'
      )
      checkAttributeTag.tagType = 'detail'
    }
    this.globalColor = this.sketchColor.hex
      ? this.sketchColor.hex
      : this.globalColor
    this.currentGlobalColorOpacity = this.sketchColor.a ? this.sketchColor.a : 1
    this.globalColorPopoverVisible = false
    // 查找原来的 颜色属性标记
    const attributeTagIndex: number = this.findAttributeTagByTagType('color')
    // 查找是否有设好的大小标记
    const attributeSizeIndex: number = this.findAttributeTagByTagType('size')
    // if (attributeTagIndex === -1) {
    //   return
    // }
    const generateColor: any = {
      circle: mapUtils.defaultPointLayerStylesSuperGlobalInfo,
      line: mapUtils.defaultLineLayerStylesSuperGlobalInfo,
      fill: mapUtils.defaultPolygonLayerStylesSuperGlobalInfo,
    }
    const sizeKeyMapping: any = {
      circle: 'circle-radius',
      line: 'line-width',
    }
    let globalSize: any = null
    // 有已经设好的大小，需要把大小设置同步过来
    if (attributeSizeIndex > -1 && sizeKeyMapping[this.currentLayer.type]) {
      globalSize =
        this.attributesAdded[attributeSizeIndex].config.paint[
          sizeKeyMapping[this.currentLayer.type]
        ]
    }
    GisStore.editTagInfoGlobalInfo({
      globalColor: this.globalColor,
      globalOpacity: this.currentGlobalColorOpacity,
      globalSize,
    })
    const config: any = generateColor[this.currentLayer.type]({
      globalColor: this.globalColor,
      globalOpacity: this.currentGlobalColorOpacity,
      globalSize,
    })
    await this.updateMapLayerByPaintValueAndLayerId(config, attributeTagIndex)
  }

  // 连续型属性 统计值 （用于颜色配置弹框）
  private successiveValues: any = []
  // 离散型属性 统计值 （用于颜色配置弹框）
  private discreteValues: any = []
  // 离散型/连续性 主题配置（用于颜色配置弹框）
  private colorThemeSettingConfig: {
    themeId?: string | number
    opacity?: number
    border?: boolean
    borderColor?: string
    borderOpacity?: number
  } = {}

  /**
   * (快捷)点击颜色编辑
   */
  public async shortcutEditColor() {
    const attributeTag: any = this.attributesAdded.find(
      (attribute: any) => attribute.tagType === 'color'
    )
    if (attributeTag) {
      const { name, desc } = attributeTag
      const dataType: number = ['decimal', 'int'].includes(desc) ? 1 : 2
      if (dataType === 1) {
        this.openSuccessiveColorPopover(name, desc)
      } else {
        this.openDiscreteColorPopover(name, desc)
      }
    } else {
      this.$message.warning('请先添加颜色属性标记!')
    }
    await GisStore.gisSaveTabInfoWithLayer()
  }

  /**
   * 打开连续型属性配色弹框
   * @param name
   * @param desc
   * @private
   */
  private async openSuccessiveColorPopover(name: string, desc: string) {
    if (!GisStore.layerAttributeFieldStatistic[name]) {
      await this.tagTypeChangeCheckStatistic(name, desc)
    }
    this.successiveValues = GisStore.layerAttributeFieldStatistic[name]
    const colorAttributeTag: any = this.attributesAdded.find(
      (attribute: any) => attribute.tagType === 'color'
    )
    if (colorAttributeTag) {
      // 用于弹框回显
      this.colorThemeSettingConfig = colorAttributeTag.config?.theme
    }
    this.successiveColorVisible = true
  }

  /**
   * 打开离散型属性配色弹框
   * @param name
   * @param desc 字段类型
   * @private
   */
  private async openDiscreteColorPopover(name: string, desc: string) {
    if (!GisStore.layerAttributeFieldStatistic[name]) {
      await this.tagTypeChangeCheckStatistic(name, desc)
    }
    this.discreteValues = GisStore.layerAttributeFieldStatistic[name]
    const colorAttributeTag: any = this.attributesAdded.find(
      (attribute: any) => attribute.tagType === 'color'
    )
    if (colorAttributeTag) {
      // 用于弹框回显
      this.colorThemeSettingConfig = colorAttributeTag.config?.theme
    }
    this.discreteColorVisible = true
  }

  /**
   * (快捷)点击大小编辑
   */
  public async shortcutEditSize() {
    this.tagLabelVisible = false
    if (this.layerType !== 'circle' && this.layerType !== 'line') {
      this.$message.warning('大小标记针对点图层和线图层生效！')
      return
    }
    if (this.tagSizeVisible) {
      this.tagSizeVisible = false
      return
    }
    const attributeTag: any = this.attributesAdded.find(
      (attribute: any) => attribute.tagType === 'size'
    )
    if (attributeTag) {
      this.tagSizeVisible = true
    } else {
      this.$message.warning('请先添加大小属性标记!')
    }
    await GisStore.gisSaveTabInfoWithLayer()
  }

  /**
   * (快捷)点击标签编辑
   */
  public shortcutEditLabel() {
    this.tagSizeVisible = false
    if (this.tagLabelVisible) {
      this.tagLabelVisible = false
      return
    }
    const attributeTag: any = this.attributesAdded.find(
      (attribute: any) => attribute.tagType === 'label'
    )
    if (attributeTag) {
      this.tagLabelVisible = true
      this.initlabelTagTypeConfig()
    } else {
      this.$message.warning('请先添加标签属性标记!')
    }
  }

  /**
   * 编辑该属性标记
   * @param attributeTag
   */
  public editAttributeTagItem(attributeTag: any) {
    const dataType: number = ['decimal', 'int'].includes(attributeTag.desc)
      ? 1
      : 2
    this.editAttributeTag(attributeTag, dataType)
  }

  /**
   * 属性标记编辑 （颜色，大小， 标签）
   * @param attributeTag
   * @param dataType  1-连续型 2-离散型
   */
  public editAttributeTag(attributeTag: any, dataType: number) {
    const { tagType, name, desc } = attributeTag
    if (tagType === 'color') {
      if (dataType === 1) {
        this.openSuccessiveColorPopover(name, desc)
      } else {
        this.openDiscreteColorPopover(name, desc)
      }
    } else if (tagType === 'size') {
      this.tagSizeVisible = true
    } else if (tagType === 'label') {
      this.tagLabelVisible = true
    }
  }

  /**
   * 通过标记类型获取属性名
   */
  public getAttributeTagByType(tagType: string) {
    return this.attributesAdded.filter(
      (attributeTag: any) => attributeTag.tagType === tagType
    )[0].name
  }

  /**
   * 离散性属性修改颜色
   */
  public discreteColorConfirm(colorInfo: any) {
    this.discreteColorVisible = false
    const findIndex: number = this.findAttributeTagByTagType('color')
    if (findIndex > -1) {
      const { name, desc } = this.attributesAdded[findIndex]
      this.changePaintColor(name, 'edit', desc, findIndex, colorInfo)
    }
  }

  /**
   * 连续型属性修改颜色
   * $emit
   */
  public successiveColorConfirm(colorInfo: any) {
    this.successiveColorVisible = false
    const findIndex: number = this.findAttributeTagByTagType('color')
    if (findIndex > -1) {
      const { name, desc } = this.attributesAdded[findIndex]
      this.changePaintColor(name, 'edit', desc, findIndex, colorInfo)
    }
  }

  /**
   * 修改大小  防抖
   * @param size
   */
  public changeFeatureSize = debounce(
    (sizes: number[]) => this._resizePointSize(sizes),
    500
  )

  /**
   * 修改要素尺寸
   */
  public _resizePointSize(sizes: number[]) {
    const findIndex: number = this.findAttributeTagByTagType('size')
    if (findIndex > -1) {
      const { name, desc } = this.attributesAdded[findIndex]
      const info: any = {
        sizes,
      }
      this.changePaintSize(name, 'edit', desc, findIndex, info)
    }
  }

  /**
   * 查找指定标志类型的属性
   * @param tagType
   * @private
   */
  private findAttributeTagByTagType(tagType: string): number {
    return this.attributesAdded.findIndex(
      (attributeTag: any) => attributeTag.tagType === tagType
    )
  }

  /**
   * 修改 标签 label
   * @param config 图层配置
   * {
   *   paint: {'text-color': string, 'text-opacity': number},
   *   layout: {'text-field': string, 'text-size': number, text-font: string}
   * }
   */
  public async confirmEditLabelSetting(config: any) {
    this.tagLabelVisible = false
    const findIndex: number = this.findAttributeTagByTagType('label')
    if (findIndex > -1) {
      const { name } = this.attributesAdded[findIndex]
      this.changeLayerLabel(name, 'edit', findIndex, { config })
    } else {
      this.$message.warning('请先添加标签属性标记!')
    }
    await GisStore.gisSaveTabInfoWithLayer()
  }

  /**
   * 修改属性标记项类型 (颜色， 大小， 标签， 详情)
   * 修改标记类型前， 检查已存在的属性标记是否已存在目标标记类型
   * 1，如果存在， 将已存在的类型设置为详情，若原类型为颜色，则将颜色恢复至全局颜色/默认颜色，
   *    若原类型为大小， 则将大小恢复至默认大小， 恢复完成后再进行设置修改
   * 2，如果不存在，正常设置修改
   * @param $event
   * @param attribute
   * @param index
   */
  private async tagTypeChange($event: any, attribute: any, index: any) {
    const currentName: string = attribute.name
    const targetTagType: string = $event.key // 目标标记类型
    const { tagType, name, desc } = this.attributesAdded[index] // 原属性标记类型
    // color -> color size -> size label -> label detail -> detail  不做处理
    if (tagType === targetTagType) {
      return
    }
    // 大小标记要求属性为数值类型
    if (this.layerType === 'fill' && targetTagType === 'size') {
      this.$message.warning('大小标记类型只对点图层和线图层生效!')
      return
    }
    // 大小标记要求属性为数值类型
    if (
      targetTagType === 'size' &&
      attribute.desc !== 'int' &&
      attribute.desc !== 'decimal'
    ) {
      this.$message.warning('大小标记类型要求属性为数值类型!')
      return
    }

    // 修改为详情 color/size/label -> detail
    if (targetTagType === 'detail') {
      GisStore.editAttributeTag({ index, tagType: 'detail' }) // 修改为详情
      // TODO 是否需要将已经生成的样式进行恢复
      this.initLayerStyleByPreTagType(tagType) // 初始化图层样式
    } else {
      // color/size/label/detail -> color/size/label 之间互相转换
      // 查找同标记类型的属性标记
      let findIndex: number = -1
      const getAttributeTag: any = this.attributesAdded.find(
        (attributeTag: any, index1: number) => {
          if (attributeTag.tagType === targetTagType) {
            findIndex = index1
            return true
          }
          return false
        }
      )
      // 无相同的属性标记
      if (!getAttributeTag) {
        this.initLayerStyleByPreTagType(tagType) // 初始化原来的属性标记
        this.tagTypeChangeUpdateLayer(index, name, targetTagType, desc)
        GisStore.editAttributeTag({ index, tagType: targetTagType })
      } else if (getAttributeTag.name === currentName) {
        // 同标记同属性名属性标记
        // 属性名相同,没必要更改
        this.$message.warning('已存在该标记类型的属性！')
      } else {
        // 同标记不同属性名属性标记
        if (targetTagType === 'color') {
          // 颜色标记需要清除上个属性标记记录的配置
          GisStore.resetTagInfoThemeConfig(findIndex)
        }
        GisStore.editAttributeTag({ index: findIndex, tagType: 'detail' }) // 将原标记修改为详情
        GisStore.editAttributeTag({ index, tagType: targetTagType }) // 将当前属性修改为目标标记
        this.tagTypeChangeUpdateLayer(index, name, targetTagType, desc)
      }

      // 标记是颜色时，自动打开配色框
      if (targetTagType === 'color') {
        this.editAttributeTagItem(attribute)
      }
    }
    await GisStore.gisSaveTabInfoWithLayer()
  }

  /**
   * 根据当前状态初始化标记状态
   */
  public initLayerStyleByPreTagType(preTagType: string) {
    // 移除原来的标记
    if (preTagType === 'label') {
      GisStore.mapboxInstance.removeLayer(`label-${this.currentLayer.id}`)
      return
    }
    const layerId: string = String(this.currentLayer.id)
    const initConfig: any = {
      globalColor: this.globalColor, // 全局颜色配置
      opacity: this.currentGlobalColorOpacity, // 透明度
      size: this.featureSize[0],
    }
    mapUtils.initPaintByLayerIdAndTagType(
      GisStore.mapboxInstance,
      layerId,
      this.layerType,
      preTagType,
      initConfig
    )
  }

  /**
   * 更新标记类型
   * @param index
   * @param columnName
   * @param key
   * @param desc
   */
  public async tagTypeChangeUpdateLayer(
    index: number,
    columnName: string,
    key: string,
    desc: string
  ) {
    // 修改当前属性标记
    if (key === 'color') {
      // 先获取该属性列统计值
      await this.tagTypeChangeCheckStatistic(columnName, desc)
      const info: any = {
        colors: [this.globalColor],
        opacity: this.currentGlobalColorOpacity,
      }
      this.changePaintColor(columnName, 'change', desc, index, info)
    } else if (key === 'size') {
      await this.tagTypeChangeCheckStatistic(columnName, desc)
      this.changePaintSize(columnName, 'change', desc, index)
    } else if (key === 'label') {
      await this.tagTypeChangeCheckStatistic(columnName, desc)
      this.changeLayerLabel(columnName, 'change', index)
    }
  }

  /**
   * 检查该属性统计是否存在
   * @param columnName
   * @param desc
   */
  public async tagTypeChangeCheckStatistic(columnName: string, desc: string) {
    if (
      GisStore.layerAttributeFieldStatistic &&
      GisStore.layerAttributeFieldStatistic[columnName]
    ) {
      return
    }
    // 先获取首页查看
    GisStore.setMapLoading(true)
    const result: any = await this.queryColumnStatistics(columnName, desc)
    if (!result) {
      GisStore.setMapLoading(false)
      return
    }
    const isSuccessiveField: boolean = ['decimal', 'int'].includes(desc)
    // 离散型多页
    if (!isSuccessiveField && result.distinctTotal > 100) {
      const { totalPages } = result.pageCount
      const pageNumbers: number[] = []
      for (let i = 2; i <= totalPages; i += 1) {
        pageNumbers.push(i)
      }
      await this.queryColumnStatisticsForAll(columnName, pageNumbers, desc)
      // 单页数据
    } else {
      GisStore.setMapLoading(false)
    }
  }

  /**
   * 如果是离散， 需要获取全部属性统计值
   * @param columnName  属性名
   * @param pageNumbers
   * @param desc
   */
  public async queryColumnStatisticsForAll(
    columnName: string,
    pageNumbers: number[],
    desc: string
  ) {
    const requests = pageNumbers.map(async (pageNumber: any) => {
      return this.queryColumnStatistics(columnName, desc, pageNumber)
    })
    GisStore.setMapLoading(true)
    await Promise.allSettled(requests)
    GisStore.setMapLoading(false)
  }

  /**
   * 获取该列的统计数据
   * @param columnName
   * @param currentPage 页码
   * @param desc 页码
   */
  public async queryColumnStatistics(
    columnName: string,
    desc: string,
    currentPage: number = 1
  ) {
    const { viewName } = this.currentLayer
    const parameters: any = {
      name: columnName,
      table: viewName,
      curPage: currentPage,
      desc,
    }
    const response: any = await GisStore.gisQueryTableColumnData(parameters)
    if (response.status === 200 && response.data.code === 100) {
      const { result } = response.data
      return result
    }
    return null
  }

  /**
   * 生成要素边框 paint
   * @param info
   * @param layerType
   */
  public generateFeatureBorderPaint(info: any, layerType: string) {
    const { border, borderColor, borderOpacity } = info
    const borderPaint: { [key: string]: any } = {}
    if (layerType === 'circle') {
      borderPaint['circle-stroke-color'] = border ? borderColor : undefined
      borderPaint['circle-stroke-opacity'] = border ? borderOpacity : 0
      borderPaint['circle-stroke-width'] = border ? 1 : 0
    } else if (layerType === 'fill') {
      borderPaint['fill-outline-color'] = border ? borderColor : undefined
    }
    return borderPaint
  }

  /**
   * 颜色编辑
   * @param name
   * @param action edit - 编辑， change - 修改
   * @param desc
   * @param index
   * @param info 信息 {colors, colorGradientMap}
   */
  public async changePaintColor(
    name: string,
    action: 'edit' | 'change',
    desc: string,
    index: number,
    info?: any
  ) {
    const paintPropertyName: string = paintPropertyNameMap[this.layerType]
    const paintPropertyOpacityName: string =
      paintPropertyOpacityNameMap[this.layerType]
    // 点图层边框， 面边框
    const borderPaint: { [key: string]: any } = this.generateFeatureBorderPaint(
      info,
      this.layerType
    )
    const borderThemeConfig = info.border
      ? {
          border: info.border,
          borderColor: info.borderColor,
          borderOpacity: info.borderOpacity,
        }
      : {}
    // 修改 标记类型， 使用默认色
    if (action === 'change') {
      const { colors, opacity } = info
      const paintValue: any[] = [
        'case',
        ['boolean', ['feature-state', 'hover'], false],
        '#aed495',
        ['boolean', ['feature-state', 'select'], false],
        '#aed495',
        colors[0],
      ]
      const config: any = {
        paint: {
          [paintPropertyName]: paintValue,
          [paintPropertyOpacityName]: opacity,
          ...borderPaint,
        },
      }
      await this.updateMapLayerByPaintValueAndLayerId(config, index)
      return
    }
    // edit 编辑颜色
    // 连续型
    if (['decimal', 'int'].includes(desc)) {
      const [min, max] = GisStore.layerAttributeFieldStatistic[name]
      const { colorGradientMap, colors, opacity, id } = info
      // 最大值最小值相等
      if (max === min) {
        const paintValue: any[] = [
          'case',
          ['boolean', ['feature-state', 'hover'], false],
          '#aed495',
          ['boolean', ['feature-state', 'select'], false],
          '#aed495',
          colors[0],
        ]
        const config: any = {
          paint: {
            [paintPropertyName]: paintValue,
            [paintPropertyOpacityName]: opacity,
            ...borderPaint,
          },
          theme: {
            // 记录配置选项，便于回显
            opacity,
            themeId: id,
            ...borderThemeConfig,
          },
        }
        await this.updateMapLayerByPaintValueAndLayerId(config, index)
      } else {
        const mapboxPaintAttributeValue: any[] = [
          'interpolate',
          ['linear'],
          ['get', name],
        ]
        const attributeValues: any = Object.keys(colorGradientMap)
          .map((key: string) => Number(key))
          .sort((a: number, b: number) => a - b)
        attributeValues.forEach((numberKey: number) => {
          mapboxPaintAttributeValue.push(numberKey)
          mapboxPaintAttributeValue.push(colorGradientMap[numberKey])
        })
        const paintValue: any[] = [
          'case',
          ['boolean', ['feature-state', 'hover'], false],
          '#aed495',
          ['boolean', ['feature-state', 'select'], false],
          '#aed495',
          mapboxPaintAttributeValue,
        ]
        const config: any = {
          paint: {
            [paintPropertyName]: paintValue,
            [paintPropertyOpacityName]: opacity,
            ...borderPaint,
          },
          theme: {
            // 记录配置选项，便于回显
            opacity,
            themeId: id,
            ...borderThemeConfig,
          },
        }
        await this.updateMapLayerByPaintValueAndLayerId(config, index)
      }
      // 离散型
    } else {
      const { colorGradientMap, otherColor, opacity, id } = info
      const mapboxPaintAttributeValue: any[] = ['match', ['get', name]]
      const attributeValues: any = Object.keys(colorGradientMap)
      attributeValues.forEach((numberKey: number) => {
        mapboxPaintAttributeValue.push(numberKey)
        mapboxPaintAttributeValue.push(colorGradientMap[numberKey])
      })
      mapboxPaintAttributeValue.push(otherColor)
      const paintValue: any[] = [
        'case',
        ['boolean', ['feature-state', 'hover'], false],
        '#aed495',
        ['boolean', ['feature-state', 'select'], false],
        '#aed495',
        mapboxPaintAttributeValue,
      ]
      const config: any = {
        paint: {
          [paintPropertyName]: paintValue,
          [paintPropertyOpacityName]: opacity,
          ...borderPaint,
        },
        theme: {
          // 记录配置选项，便于回显
          opacity,
          themeId: id,
          ...borderThemeConfig,
        },
      }
      await this.updateMapLayerByPaintValueAndLayerId(config, index)
    }
  }

  /**
   * 大小编辑 (标签大小针对点图层和线图层生效, 且要求字段为数值类型)
   * @param name
   * @param action
   * @param desc
   * @param index
   * @param info  [minSize, maxSize]
   */
  public async changePaintSize(
    name: string,
    action: 'edit' | 'change',
    desc: string,
    index: number,
    info?: any
  ) {
    // 如果没有该列统计数据， 则先获取
    if (!GisStore.layerAttributeFieldStatistic[name]) {
      GisStore.setMapLoading(true)
      await this.tagTypeChangeCheckStatistic(name, desc)
      GisStore.setMapLoading(false)
    }
    const [min, max] = GisStore.layerAttributeFieldStatistic[name]
    let [minSize, maxSize] = this.featureSize
    if (info) {
      ;[minSize, maxSize] = info.sizes
    }
    const sizeGradient: any = generateSizeGradient(
      min,
      max,
      minSize,
      maxSize,
      10,
      name
    ) // 生成大小梯度
    const paintPropertyName: string =
      this.layerType === 'circle' ? 'circle-radius' : 'line-width'
    const config: any = {
      paint: {
        [paintPropertyName]: sizeGradient,
      },
      size: [minSize, maxSize],
    }
    await this.updateMapLayerByPaintValueAndLayerId(config, index)
    await GisStore.gisSaveTabInfoWithLayer()
  }

  /**
   * 根据图层id 和标记属性 key - value 更新渲染地图
   * @param config
   * @param index
   * @private
   */
  private async updateMapLayerByPaintValueAndLayerId(
    config: any,
    index?: number
  ) {
    const layerId: string = String(this.currentLayer.id)
    // 更新图层演示
    mapUtils.updateLayerStyles(GisStore.mapboxInstance, layerId, config)
    // 存储图层样式
    if (index !== undefined && index > -1) {
      GisStore.editTagInfoAttributeTagValue({ index, config })
    }
    // layer.data.hasArrow && layer.visible === 1
    if (this.currentLayer.type === 'line' && this.currentLayer.data?.hasArrow) {
      mapUtils.updateArrowLayer(GisStore.mapboxInstance, this.currentLayer)
    }
    await GisStore.gisSaveTabInfoWithLayer()
  }

  /**
   * 获取前一个图层id
   * @param layerId
   * @private
   */
  private getLayerBeforeId(layerId: number) {
    const LayerList: any[] = GisStore.layerList
    const index: number = LayerList.findIndex(
      (layer: any) => layer.id === layerId
    )
    let beforeId: string | null = 'base-empty-layer'
    if (index > 0 && LayerList[index - 1].id) {
      const layerIdString: string = String(LayerList[index - 1].id)
      const beforeIdExist: boolean =
        !!GisStore.mapboxInstance.getLayer(layerIdString)
      beforeId = beforeIdExist ? layerIdString : 'base-empty-layer'
    }
    return beforeId
  }

  /**
   * 修改标签 / 给当前图层添加或者修改 label
   */
  public changeLayerLabel(
    name: string,
    action: 'edit' | 'change' = 'edit',
    index: number,
    info?: any
  ) {
    const labelLayerId: string = `label-${this.currentLayer.id}`
    const layerIsExist: boolean =
      !!GisStore.mapboxInstance.getLayer(labelLayerId)
    // 如果是切换标记类型
    if (action === 'change') {
      const config: any = {
        paint: {
          ...defaultLabelTagLayerStyle.paint,
        },
        layout: {
          ...defaultLabelTagLayerStyle.layout,
          'symbol-placement': this.layerType === 'line' ? 'line' : 'point',
          'text-ignore-placement': true,
          'text-field': ['get', name],
        },
      }
      if (layerIsExist) {
        mapUtils.updateLayerStyles(
          GisStore.mapboxInstance,
          labelLayerId,
          config
        )
      } else {
        const beforeId: string = this.getLayerBeforeId(this.currentLayer.id)
        mapUtils.addSymbolLabelLayerByConfig(
          GisStore.mapboxInstance,
          this.currentLayer,
          config,
          beforeId
        )
      }
      GisStore.editTagInfoAttributeTagValue({ index, config })
    } else {
      const config: any = {
        paint: {
          ...defaultLabelTagLayerStyle.paint,
          ...info.config.paint,
        },
        layout: {
          ...defaultLabelTagLayerStyle.layout,
          ...info.config.layout,
          'symbol-placement': this.layerType === 'line' ? 'line' : 'point',
          'text-ignore-placement': true,
          'text-field': ['get', name],
        },
      }
      mapUtils.updateLayerStyles(GisStore.mapboxInstance, labelLayerId, config)
      GisStore.editTagInfoAttributeTagValue({ index, config })
    }
  }

  /**
   * 属性标记的操作
   * @param $event
   * @param attributeTag
   * @param index
   */
  public async menuAction($event: any, attributeTag: any, index: number) {
    $event.domEvent.stopPropagation()
    const { key } = $event
    if (key === 'delete') {
      await this.deleteAttributeTag(attributeTag.tagType, index)
    } else if (key === 'edit') {
      this.editAttributeTagItem(attributeTag)
    } else if (key === 'view-source-data') {
      const attribute: { desc: string; name: string; type: number } = {
        desc: attributeTag.desc,
        name: attributeTag.name,
        type: attributeTag.type,
      }
      if (!GisStore.selectLayer) {
        GisStore.setSelectLayer(this.currentLayer)
      }
      GisStore.setViewDataLayerTime()
      this.$nextTick(() => {
        GisStore.setSelectedColumns([attribute]) // 卡片
        GisStore.setTableSelectColumns([attribute]) // 数据表 - 列
      })
    }
  }

  /**
   * 删除属性标记
   * @param tagType
   * @param index
   */
  public async deleteAttributeTag(tagType: string, index: number) {
    this.initLayerStyleByPreTagType(tagType)
    GisStore.deleteAttributeTag(index)
    await GisStore.gisSaveTabInfoWithLayer()
  }

  public editDetail() {}
}
</script>

<style lang="less" scoped>
@import '@/styles/scroll-bar';
@import '@/styles/common-style.less';

.gis-layer-management {
  height: 100%;
  position: relative;
  user-select: none;

  .module-disabled {
    background-color: #ededf4;
    cursor: not-allowed;
    height: 100%;
    left: 0;
    opacity: 0.5;
    position: absolute;
    top: 0;
    width: 100%;
    z-index: 10;
  }

  // 头
  .header {
    box-sizing: content-box;
    height: 20px;
    line-height: 20px;
    //margin: 1
    padding: 12px 16px;

    .header-title {
      align-items: center;
      color: #b1b1b1;
      display: flex;
      justify-content: space-between;
      // 数据源 算子  icon
      .type-icon-name {
        align-items: center;
        display: flex;
        font-size: 20px;

        .header-name {
          color: #5d637e;
          font-size: 14px;
          font-weight: 700;
          letter-spacing: 1px;
        }
      }
    }

    .name {
      color: #4b4b4b;
    }
  }

  // 属性
  .layer-tag-content {
    height: calc(100% - 44px);
    overflow-y: auto;
    user-select: none;

    /deep/.ant-divider {
      color: rgba(34, 36, 50, 0.5);
      font-size: 12px;
      font-weight: 400;
      letter-spacing: 1.12px;
      margin: 0 0 12px;
      padding: 0 12px;

      .ant-divider-inner-text {
        padding: 0 12px;
      }
    }

    .value-select {
      align-items: center;
      display: flex;
      margin-bottom: 12px;
      padding: 0 12px;
      width: 100%;

      .color-select {
        height: 20px;
        margin-left: 10px;
        width: 20px;

        .select-color-popover {
          display: inline-block;
          height: 100%;
          width: 100%;
        }
      }
    }

    .no-text-divider {
      padding: 0 12px;
      width: 100%;
    }

    .tag-list {
      display: flex;
      flex-wrap: wrap;
      padding: 0 4px 0 12px;

      .tag-item {
        align-items: center;
        background: #fff;
        border: 1px solid #c5c9ff;
        border-radius: 2px;
        cursor: pointer;
        display: flex;
        flex-direction: column;
        height: 52px;
        justify-content: center;
        margin: 0 8px 8px 0;
        width: 52px;

        .tag-item-icon {
          display: inline-block;
          font-size: 20px;
        }

        .tag-item-text {
          color: #5d637e;
          font-size: 11px;
          font-weight: 400;
          letter-spacing: 1px;
          line-height: 16px;
        }

        &:hover {
          background: rgba(103, 113, 252, 0.1);
          border: 1px solid rgba(105, 115, 255, 0.6);
          border-radius: 2px;
        }
      }

      .tag-item-active {
        background: rgba(103, 113, 252, 0.1);
        border: 1px solid rgba(105, 115, 255, 0.6);
        border-radius: 2px;
      }

      .enter-tag-section {
        border: 1px solid rgba(105, 115, 255, 0.6);
      }

      .enter-tag-type {
        background: rgba(103, 113, 252, 0.1);
      }
    }

    .tag-setting-list {
      padding: 0 12px;

      .setting-list-item {
        align-items: center;
        display: flex;
        height: 32px;
        line-height: 32px;
        width: 100%;

        .ant-dropdown-icon {
          cursor: pointer;
          height: 24px;
          line-height: 24px;
          width: 32px;
        }

        .attribute-tag-item {
          align-items: center;
          border: 1px solid transparent;
          border-radius: 16px;
          display: flex;
          height: 22px;
          justify-content: space-between;
          padding: 0 9px;
          width: calc(100% - 32px);

          .item-name {
            display: inline-block;
            width: 100%;
          }

          .delete-attribute-tag {
            cursor: pointer;
            display: none;
            height: 16px;
            line-height: 16px;
            width: 16px;
          }

          .ant-dropdown-icon {
            //background-color: rgba(105, 115, 255, 0.1);
            //border-radius: 50%;
            cursor: pointer;
            display: none;
            height: 16px;
            line-height: 16px;
            width: 16px;
          }

          &:hover {
            border: 1px solid #cbceff;

            .item-name {
              width: calc(100% - 40px);
            }

            .delete-attribute-tag {
              display: inline-block;
            }

            .ant-dropdown-icon {
              display: inline-block;
            }
          }
        }
      }
    }
  }
}
</style>
<style lang="less">
// 全局颜色选择
.gis-popover-color-picker {
  border-radius: 4px;

  .ant-popover-content {
    width: 220px;

    .ant-popover-inner {
      box-shadow: 0 0 8px #c5c9ff;

      .ant-popover-inner-content {
        padding: 0;
      }
    }
  }

  .vc-sketch {
    border-radius: 4px 4px 0 0;
    box-shadow: none;
  }

  .cancel-confirm {
    display: flex;
    justify-content: flex-end;
    padding: 6px 12px;

    .cancel-button {
      margin-right: 12px;
    }
  }
}

// 标记大小设置
.gis-popover-size-slider {
  .ant-popover-content {
    width: 200px;

    .ant-popover-inner {
      box-shadow: 0 0 8px #c5c9ff;

      .ant-popover-inner-content {
        background: #fff;
        border-radius: 2px;
        box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.18);
        height: 40px;
        overflow: hidden;
        padding: 0 12px;
        width: 200px;
      }
    }
  }
}

.gis-popover-label {
  .ant-popover-content {
    width: 233px;

    .ant-popover-inner {
      box-shadow: 0 0 8px #c5c9ff;

      .ant-popover-inner-content {
        background: #fff;
        border-radius: 2px;
        box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.18);
        overflow: hidden;
        padding: 0;
        width: 233px;
      }
    }
  }
}
</style>
